﻿using Microsoft.Win32;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using FFmpeg.AutoGen;

namespace CvTestWpfApp
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : System.Windows.Window
    {
        private D3DImage d3dImg;

        public MainWindow()
        {
            InitializeComponent();
        }

        private ConcurrentQueue<OpenCvSharp.Mat> _matsQueue;
        private WriteableBitmap _writeBitmap;
        /// <summary>
        /// 当前选择的码率
        /// </summary>
        private OpenCvSharp.Size _tranformSize = new OpenCvSharp.Size(0, 0);
        private Int32Rect _rect;
        private bool playing;
        private OpenCvSharp.Mat _tranformFrame = new OpenCvSharp.Mat();

        private void WinLoaded(object sender, RoutedEventArgs e)
        {
            cameraImg.Source = d3dImg;
            _matsQueue = new ConcurrentQueue<OpenCvSharp.Mat>();
            CompositionTarget.Rendering += CompositionTargetRendering;
        }

        private void WinUnloaded(object sender, RoutedEventArgs e)
        {
            CompositionTarget.Rendering -= CompositionTargetRendering;
        }

        private void CompositionTargetRendering(object sender, EventArgs e)
        {
            bool getRs = _matsQueue.TryDequeue(out var mat);
            if (getRs)
            {
                LoadImgByOpenCvMat(mat);
            }
            mat?.Dispose();
        }

        private void LoadImgByOpenCvMat(OpenCvSharp.Mat frame)
        {
            // 转码率
            //if (_tranformSize.Height != 0 && frame.Height != _tranformSize.Height)
            //{
            //    OpenCvSharp.Cv2.Resize(frame, _tranformFrame, _tranformSize);
            //    frame = _tranformFrame;
            //}
            //if (_rect.Height != frame.Height)
            //{
            //    _rect = new Int32Rect(0, 0, frame.Width, frame.Height);
            //}

            using System.Drawing.Bitmap bitmap = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(frame);
            System.Drawing.Imaging.BitmapData data = bitmap.LockBits(
                new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height),
                System.Drawing.Imaging.ImageLockMode.ReadOnly,
                System.Drawing.Imaging.PixelFormat.Format32bppArgb);

            Dispatcher.Invoke(() =>
            {
                if (_writeBitmap == null)
                {
                    _writeBitmap = new WriteableBitmap(frame.Width, frame.Height, 96, 96, PixelFormats.Bgra32, null); //BitmapPalettes.Gray256
                    cameraImg.Source = _writeBitmap;
                    _rect = new Int32Rect(0, 0, frame.Width, frame.Height);
                }
                _writeBitmap.Lock();
                _writeBitmap.WritePixels(_rect, data.Scan0, (4 * data.Width * data.Height), data.Stride);
                _writeBitmap.Unlock();
            });
            bitmap.UnlockBits(data);
            bitmap.Dispose();

            frame.Dispose();
        }

        private void OpenCameraBtnClick(object sender, RoutedEventArgs e)
        {
            OpenCvLib.MediaCapture capture = new OpenCvLib.MediaCapture();
            bool openRs = capture.OpenCamera();
            if (!openRs)
            {
                MessageBox.Show("摄像头打开失败", "提示", MessageBoxButton.OK);
                return;
            }
            playing = true;
            _writeBitmap = null;
            _ = Task.Factory.StartNew(async () =>
            {
                int fps = Convert.ToInt32(capture.Fps);
                int ms = 1000 / fps;
                do
                {
                    OpenCvSharp.Mat mat = capture.ReadFrame();
                    _matsQueue.Enqueue(mat);
                    await Task.Delay(ms);
                } while (playing);

            });
        }

        private void OpenFileBtnClick(object sender, RoutedEventArgs e)
        {
            string file = null;
            OpenFileDialog dialog = new OpenFileDialog
            {
                Filter = "视频文件|*.mp4;*.mp3;*.avi;*.mov;*.rmvb;*.flv",
                RestoreDirectory = true
            };
            if (dialog.ShowDialog() == true)
            {
                file = dialog.FileName;
            }
            if (string.IsNullOrEmpty(file)) { return; }

            OpenCvLib.MediaCapture capture = new OpenCvLib.MediaCapture();
            bool openRs = capture.OpenVideo(file);
            if (!openRs)
            {
                MessageBox.Show("文件打开失败", "提示", MessageBoxButton.OK);
                return;
            }
            _writeBitmap = null;
            playing = true;
            _ = Task.Factory.StartNew(async () =>
            {
                int fps = Convert.ToInt32(capture.Fps);
                int ms = 1000 / fps;
                do
                {
                    OpenCvSharp.Mat mat = capture.ReadFrame();
                    _matsQueue.Enqueue(mat);
                    await Task.Delay(ms);
                } while (playing);
            });

        }

        private void StopBtnClick(object sender, RoutedEventArgs e)
        {
            playing = false;
        }

        #region d3d
        private void RenderD3D(IntPtr surface)
        {
            Int32Rect showRect = new Int32Rect(0, 0, d3dImg.PixelWidth, d3dImg.PixelHeight);

            this.Dispatcher.BeginInvoke(new Action(() =>
            {
                if (d3dImg.IsFrontBufferAvailable && surface != IntPtr.Zero)
                {
                    d3dImg.Lock();
                    d3dImg.SetBackBuffer(D3DResourceType.IDirect3DSurface9, surface);
                    d3dImg.AddDirtyRect(showRect);
                    d3dImg.Unlock();
                }
            }));
        }
        #endregion

    }
}